#include <algorithm>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "CLComString.h"
#include "clcomfuncs.h"
#define CLComString_DELBUFFERS(P){delete[] P; P = NULL;}

CLComString::CLComString()
{
    m_str = "";
    m_tempWCHars = nullptr;
}

CLComString::CLComString(const char* lpsz)
{
    m_str = lpsz;
}
CLComString::CLComString(const wchar_t* lpsz)
{
    Append(lpsz);
}
CLComString::CLComString(const string& src)
{
    m_str = src;
}
CLComString::CLComString(long long nValue)
{
    SmallFormat("%lld", nValue);
}
CLComString::CLComString(int nValue)
{
    SmallFormat("%d", nValue);
}
CLComString::CLComString(double dValue)
{
    SmallFormat("%f", dValue);
}

CLComString::CLComString(const CLComString& src)
{
    m_str = src.m_str;
}

CLComString::~CLComString(){}

size_t CLComString::GetLength() const
{
    return m_str.length();
}
void CLComString::SetHaveChinese(bool bflag)
{
    m_bhaveChinese = bflag;
}

long long CLComString::GetBigInt()const
{
    return atoll(m_str.c_str());
}
int CLComString::GetInt()const
{
    return atoi(m_str.c_str());
}
double CLComString::GetDouble()const
{
    return atof(m_str.c_str());
}
bool CLComString::GetBool()const
{
    return atoi(m_str.c_str()) > 0;
}
const char* CLComString::GetChars()const
{
    return m_str.c_str();
}

const wchar_t*  CLComString::GetWChars()
{
    if (m_tempWCHars != nullptr)
    {
        return m_tempWCHars;
    }

    CLComFuncs::multibyte2widechar(m_str.c_str(), &m_tempWCHars);

    return m_tempWCHars;
}
void CLComString::ReleaseWChars()
{
    if (m_tempWCHars)
    {
        delete[] m_tempWCHars;
        m_tempWCHars = nullptr;
    }
}

bool CLComString::IsEmpty() const
{
    return m_str.length() == 0;
}
void CLComString::Reverse()
{
    if (m_str.length() == 0)
    {
        return;
    }
    char temp;
    int start = 0;
    size_t end = m_str.size() - 1;

    while (start < (int)end)
    {
        temp = m_str[start];
        m_str[start] = m_str[end];
        m_str[end] = temp;
        ++start;
        --end;
    }
}

void CLComString::Erase(size_t nIdex)
{
    m_str.erase(nIdex);
}
void CLComString::Erase(CLComString startstring)
{
    Erase(this->Find(startstring));
}

char CLComString::GetAt(size_t nIndex) const
{
    if ((m_str.length() == 0) ||
        (nIndex >= m_str.length()))
    {
        return INVALID_CHAR;
    }
    return m_str[nIndex];
}

void CLComString::Append(const wchar_t*  pstr)
{
    if (!pstr)
    {
        return;
    }
    char* p = nullptr;
    CLComFuncs::widechar2multibyte(pstr, &p);
    if (p == nullptr)
    {
        return ;
    }
    m_str += p;

    CLComString_DELBUFFERS(p);
}
void CLComString::Append(const char* pstr)
{
    if (!pstr)
    {
        return;
    }
    m_str += pstr;
}
void CLComString::Append(const CLComString& src)
{
    m_str += src.m_str;
}
void CLComString::Append(const string& src)
{
    m_str += src;
}

void CLComString::SetAt(size_t nIndex, char ch)
{
    if (nIndex >= m_str.length())
    {
        return;
    }
    m_str[nIndex] = ch;
}

void CLComString::Empty()
{
    m_str = "";
}

char CLComString::operator[] (size_t nIndex) const
{
    return m_str[nIndex];
}
const CLComString& CLComString::operator=(int nValue)
{
    CLComString tempstr;

    tempstr += nValue;

    Empty();
    Append(tempstr);

    return *this;
}
const CLComString& CLComString::operator=(long long nValue)
{
    CLComString tempstr;

    tempstr += nValue;

    Empty();
    Append(tempstr);

    return *this;
}
const CLComString& CLComString::operator=(double dValue)
{
    CLComString tempstr;

    tempstr += dValue;

    Empty();
    Append(tempstr);

    return *this;
}
const CLComString& CLComString::operator=(const CLComString& src)
{
    Empty();

    Append(src);

    return *this;
}
const CLComString& CLComString::operator=(const wchar_t* pstr)
{
    Empty();

    Append(pstr);

    return *this;
}
const CLComString& CLComString::operator=(const char* pstr)
{
    m_str = pstr;

    return *this;
}
const CLComString& CLComString::operator=(const string& src)
{
    m_str = src;

    return *this;
}

const CLComString& CLComString::operator+=(const char* lpStr)
{
    if (lpStr)
    {
        m_str += lpStr;
    }
    return *this;
}
const CLComString& CLComString::operator+=(const wchar_t* lpwStr)
{
    if (lpwStr)
    {
        Append(lpwStr);
    }
    return *this;
}
const CLComString& CLComString::operator+=(const CLComString& src)
{
    Append(src);
    return *this;
}
const CLComString& CLComString::operator+=(char ch)
{
    m_str += ch;

    return *this;
}
const CLComString& CLComString::operator+=(long long nValue)
{
    string tempstr = m_str;

    this->Format("%lld", nValue);

    tempstr += m_str;

    m_str = tempstr;

    return *this;
}
const CLComString& CLComString::operator+=(int nValue)
{
    string tempstr = m_str;

    this->Format("%d", nValue);

    tempstr += m_str;

    m_str = tempstr;

    return *this;
}
void CLComString::AddInt(long long nValue, int len)
{
    char buffer[64] = { 0 };
    sprintf(buffer, "%lld", nValue);

    int nGap = (len - (int)strlen(buffer));
    for (int i = 0; i < nGap; ++i)
    {
        m_str += "0";
    }
    m_str += buffer;
}
void CLComString::AddInt(int nValue, int len)
{
    char buffer[64] = { 0 };
    sprintf(buffer, "%d", nValue);

    int nGap = (len - (int)strlen(buffer));
    for (int i = 0; i < nGap; ++i)
    {
        m_str += "0";
    }
    m_str += buffer;
}
const CLComString& CLComString::operator+=(double dValue)
{
    string tempstr = m_str;

    this->Format("%f", dValue);

    tempstr += m_str;

    m_str = tempstr;

    return *this;
}
const CLComString& CLComString::operator+=(const string& src)
{
    Append(src);
    return *this;
}

CLComString CLComString::operator+(const CLComString& src) const
{
    CLComString sTemp = *this;
    sTemp.Append(src);
    return sTemp;
}

CLComString CLComString::operator+(const char* lpStr) const
{
    if (!lpStr)
    {
        return *this;
    }
    CLComString sTemp = *this;
    sTemp.Append(lpStr);

    return sTemp;
}
CLComString CLComString::operator+(const wchar_t* pstr) const
{
    if (!pstr)
    {
        return *this;
    }
    CLComString sTemp = *this;
    sTemp.Append(pstr);

    return sTemp;
}
CLComString CLComString::operator+(double dValue) const
{
    CLComString sTemp = *this;
    sTemp += dValue;

    return sTemp;
}
CLComString CLComString::operator+(int nValue) const
{
    CLComString sTemp = *this;
    sTemp += nValue;

    return sTemp;
}
CLComString CLComString::operator+(long long nValue) const
{
    CLComString sTemp = *this;
    sTemp += nValue;

    return sTemp;
}
CLComString CLComString::operator+(const string& src) const
{
    CLComString sTemp = *this;
    sTemp += src;

    return sTemp;
}

bool CLComString::operator == (const char* str) const
{
    return (Compare(str) == 0);
}
bool CLComString::operator != (const char* str) const
{
    return (Compare(str) != 0);
}
bool CLComString::operator <= (const char* str) const
{
    return (Compare(str) <= 0);
}
bool CLComString::operator <  (const char* str) const
{
    return (Compare(str) < 0);
}
bool CLComString::operator >= (const char* str) const
{
    return (Compare(str) >= 0);
}
bool CLComString::operator >  (const char* str) const
{
    return (Compare(str) > 0);
}

bool CLComString::operator == (const CLComString& str) const
{
    return (Compare(str.GetChars()) == 0);
}
bool CLComString::operator != (const CLComString& str) const
{
    return (Compare(str.GetChars()) != 0);
}
bool CLComString::operator <= (const CLComString& str) const
{
    return (Compare(str.GetChars()) <= 0);
}
bool CLComString::operator <  (const CLComString& str) const
{
    return (Compare(str.GetChars()) < 0);
}
bool CLComString::operator >= (const CLComString& str) const
{
    return (Compare(str.GetChars()) >= 0);
}
bool CLComString::operator >  (const CLComString& str) const
{
    return (Compare(str.GetChars()) > 0);
}

bool operator == (const char* str, const CLComString& str2)
{
    CLComString temp = str;
    return temp == str2;
}
bool operator != (const char* str, const CLComString& str2)
{
    CLComString temp = str;
    return temp != str2;
}
bool operator <= (const char* str, const CLComString& str2)
{
    CLComString temp = str;
    return temp <= str2;
}
bool operator <  (const char* str, const CLComString& str2)
{
    CLComString temp = str;
    return temp < str2;
}
bool operator >= (const char* str, const CLComString& str2)
{
    CLComString temp = str;
    return temp >= str2;
}
bool operator >  (const char* str, const CLComString& str2)
{
    CLComString temp = str;
    return temp > str2;
}
CLComString::operator string()
{
    return m_str;
}
string CLComString::operator()(string)
{
    return m_str;
}
CLComString::operator const char*()
{
    return m_str.c_str();
}

int CLComString::Compare(const char* lpsz) const
{
    return strcmp(m_str.c_str(), lpsz);
}

int CLComString::CompareNoCase(const char* lpsz) const
{
#ifdef Q_OS_LINUX
    return strcasecmp(m_str.c_str(), lpsz);
#else
    return _stricmp(m_str.c_str(), lpsz);
#endif
}

void CLComString::MakeUpper()
{
    for (unsigned int i = 0; i < m_str.size(); ++i)
    {
        if (CLComFuncs::IsChinese(m_str[i]))
        {
            ++i;
        }
        else
        {
            if ('a' <= m_str[i] && 'z' >= m_str[i])
            {
                m_str[i] = m_str[i] - 32;
            }
        }
    }
}

void CLComString::MakeLower()
{
    for (unsigned int i = 0; i < m_str.size(); ++i)
    {
        if (CLComFuncs::IsChinese(m_str[i]))
        {
            ++i;
        }
        else
        {
            if ('A' <= m_str[i] && 'Z' >= m_str[i])
            {
                m_str[i] = m_str[i] + 32;
            }
        }
    }
}

CLComString CLComString::Left(size_t iLength) const
{
    if (iLength > GetLength()) iLength = GetLength();

    string tempstr = m_str.substr(0, iLength);
    return CLComString(tempstr);
}

CLComString CLComString::Substr(size_t iPos, size_t iLength) const
{
    string tmpstr = m_str.substr(iPos, iLength);
    return CLComString(tmpstr);
}

CLComString CLComString::Right(size_t iLength) const
{
    if (iLength > m_str.length())
    {
        return CLComString(m_str);
    }
    string tempstr = m_str.substr(m_str.length() - iLength);
    return CLComString(tempstr);
}

CLComString CLComString::Substr(CLComString startstr,
    CLComString endstr) const
{
    CLComString tempstr = m_str;

    int nFindIndex =
        tempstr.ReverseFind(startstr,
            tempstr.GetLength() - 1);

    int nFindDIndex =
        tempstr.ReverseFind(endstr,
            tempstr.GetLength() - 1);

    if (nFindDIndex == -1
        || nFindIndex == -1
        || nFindIndex >= nFindDIndex)
    {
        return "";
    }
    int nCount = nFindDIndex - nFindIndex - 1;
    tempstr = tempstr.Substr(nFindIndex + 1, nCount);

    return tempstr;
}


size_t CLComString::Find(const char* pstr, size_t iPos /*= 0*/) const
{
    size_t index = INVALID_INDEX;
    if (iPos >= GetLength())
    {
        return index;
    }
    if (m_bhaveChinese)
    {
        index = CLComFuncs::FindMix(m_str, pstr, iPos, true);
    }
    else
    {
        index = m_str.find(pstr, iPos);
        if (index == string::npos)
        {
            index = INVALID_INDEX;
        }
    }

    return INVALID_INDEX;
}

size_t CLComString::Find(const wchar_t*  pstrSub, size_t iPos /*= 0*/) const
{
    if (iPos >= GetLength())
    {
        return INVALID_INDEX;
    }

    char* pstr = nullptr;

    CLComFuncs::widechar2multibyte(pstrSub, &pstr);
    if (!pstr)
    {
        return INVALID_INDEX;
    }
    size_t nRet = string::npos;
    if (m_bhaveChinese)
    {
        nRet = CLComFuncs::FindMix(m_str, pstr, iPos, true);
    }
    else
    {
        nRet = m_str.find(pstr, iPos);
        if (nRet == string::npos)
        {
            nRet = INVALID_INDEX;
        }
    }
    CLComString_DELBUFFERS(pstr);

    return nRet;
}
size_t CLComString::Find(const CLComString& src, size_t iPos) const
{
    return Find(src.m_str.c_str(), iPos);
}

size_t CLComString::ReverseFind(const char*  pstr, size_t iPos) const
{
    if (iPos >= GetLength())
    {
        return INVALID_INDEX;
    }
    size_t index = INVALID_INDEX;
    if (m_bhaveChinese)
    {
        index = CLComFuncs::FindMix(m_str, pstr, iPos, false);
    }
    else
    {
        index = m_str.rfind(pstr, iPos);
        if (index == string::npos)
        {
            index = INVALID_INDEX;
        }
    }
    return index;
}
size_t CLComString::ReverseFind(const wchar_t*  pstrSub, size_t iPos) const
{
    if (iPos >= GetLength())
    {
        return INVALID_INDEX;
    }

    char* pstr = nullptr;

    CLComFuncs::widechar2multibyte(pstrSub, &pstr);
    if (!pstr)
    {
        return INVALID_INDEX;
    }
    size_t nRet = ReverseFind(pstr, iPos);

    CLComString_DELBUFFERS(pstr);

    return nRet;
}
size_t CLComString::ReverseFind(const CLComString& src, size_t iPos) const
{
    return ReverseFind(src.m_str.c_str(), iPos);
}

void CLComString::Replace(const char*  pstrFrom, const char*  pstrTo)
{
    CLComFuncs::ReplaceSubstr(m_str, pstrFrom, pstrTo);
}
void CLComString::Replace(const wchar_t* pstrFrom, const wchar_t* pstrTo)
{
    char* pstrsrc = nullptr;
    char* pstrdst = nullptr;

    CLComFuncs::widechar2multibyte(pstrFrom, &pstrsrc);
    if (!pstrFrom)
    {
        return ;
    }
    CLComFuncs::widechar2multibyte(pstrTo, &pstrdst);
    if (!pstrTo)
    {
        return ;
    }
    CLComFuncs::ReplaceSubstr(m_str, pstrsrc, pstrdst);

    CLComString_DELBUFFERS(pstrsrc);
    CLComString_DELBUFFERS(pstrdst);
}
void CLComString::Replace(const CLComString& src, const CLComString& dst)
{
    CLComFuncs::ReplaceSubstr(m_str, src.m_str, dst.m_str);
}
int  CLComString::Format(const char* pstrFormat, ...)
{
    int nRet;
    va_list Args;

    va_start(Args, pstrFormat);
    nRet = InnerFormat(pstrFormat, Args);
    va_end(Args);

    return nRet;
}
int  CLComString::SmallFormat(const char* pstrFormat, ...)
{
    char szBuffer[64] = { 0 };
    va_list argList;
    va_start(argList, pstrFormat);

    int iRet =  0;
#ifdef Q_OS_WINDOWS
    iRet = ::_vsnprintf(szBuffer, sizeof(szBuffer), pstrFormat, argList);
#else
    iRet = vsnprintf(szBuffer, sizeof(szBuffer), pstrFormat, argList);
#endif
    va_end(argList);

    Empty();
    Append(szBuffer);

    return iRet;
}
int CLComString::InnerFormat(const char* pstrFormat, va_list Args)
{
    int nLen = 0;
    int totalLen = 0;
    char *szBuffer = nullptr;
#ifdef Q_OS_WINDOWS
    nLen = _vsnprintf(NULL, 0, pstrFormat, Args);
#else
    nLen = vsnprintf(NULL, 0, pstrFormat, Args);
#endif
    totalLen = (nLen + 1)*sizeof(char);
    szBuffer = (char*)malloc(totalLen);

    if (szBuffer)
    {
        memset(szBuffer, 0, totalLen);
#ifdef Q_OS_WINDOWS
        nLen = _vsnprintf(szBuffer, size_t(nLen) + 1, pstrFormat, Args);
#else
        nLen = vsnprintf(szBuffer, size_t(nLen) + 1, pstrFormat, Args);
#endif
        Empty();
        Append(szBuffer);

        free(szBuffer);
    }
    else
    {
        nLen = 0;
    }
    return nLen;
}
bool CLComString::ClearString(const CLComString& strStart, const CLComString& strEnd, bool isClearAll, int end)
{
    int indexStart = -1;
    int indexEnd = -1;
    int startFind = 0;
    bool isFirst = true;

    if (0 == m_str.size())
    {
        return false;
    }

    if (0 == strStart.GetLength() && 0 == strEnd.GetLength())
    {
        return false;
    }

    do
    {
        if (0 == strEnd.GetLength())
        {
            indexStart = Find(strStart, startFind);
            if (-1 == indexStart || (-1 != end && indexStart > end))
            {
                break;
            }
            m_str.erase(indexStart, strStart.GetLength());
            isFirst = false;
            continue;
        }
        else if (0 == strStart.GetLength())
        {
            indexStart = Find(strEnd, startFind);

            if (-1 == indexEnd)
            {
                break;
            }

            indexEnd = indexEnd + strEnd.GetLength();
            if (-1 != end && indexEnd > end)
            {
                break;
            }
            m_str.erase(indexStart, size_t(indexEnd) - indexStart);
            isFirst = false;
            continue;
        }
        else
        {
            indexEnd = Find(strEnd, startFind);

            if (-1 == indexEnd)
            {
                break;
            }

            indexEnd = indexEnd + strEnd.GetLength();
            if (-1 != end && indexEnd > end)
            {
                break;
            }

            indexStart = ReverseFind(strStart, indexEnd - strEnd.GetLength());

            if (-1 == indexStart)
            {
                startFind = indexEnd + strEnd.GetLength();
                continue;
            }
            else
            {
                isFirst = false;
                m_str.erase(indexStart, size_t(indexEnd) - indexStart);
            }
        }
    } while (isClearAll);

    if (isFirst)
    {
        return false;
    }
    else
    {
        return true;
    }
}
int CLComString::FilterString(const CLComString& beSplited, const CLComString&  spliter, size_t start, bool forward)
{
    if (start >= GetLength() || 0 == spliter.GetLength() || 0 == beSplited.GetLength() || 0 == GetLength())
    {
        return start;
    }
    vector<CLComString> vp;
    vector<CLComString>::iterator it;
    SplitString(vp, spliter, beSplited, false);

    bool flag = false;
    size_t index = start;
    if (forward)
    {
        for (int i = start; i < (int)m_str.size();)
        {
            for (it = vp.begin(); it != vp.end(); ++it)
            {
                for (int j = 0; 0 != (*it)[j];)
                {
                    if ((*it)[j] == m_str[size_t(i) + j])
                    {
                        ++j;
                        if (0 == (*it)[j])
                        {
                            i = i + j;
                            index = i;
                            flag = true;
                            break;
                        }

                    }
                    else
                    {
                        break;
                    }
                }
            }
            if (!flag)
            {
                break;
            }
            else
            {
                flag = false;
            }
        }
    }
    else
    {
        for (int i = start; 0 <= i;)
        {
            for (it = vp.begin(); it != vp.end(); ++it)
            {
                for (int j = (*it).GetLength() - 1, k = 0; 0 <= j; --j, ++k)
                {
                    if ((*it)[j] == m_str[size_t(i) - k])
                    {
                        if (0 == j)
                        {
                            index = i - k;
                            i = index - 1;
                            flag = true;
                            break;
                        }

                    }
                    else
                    {
                        break;
                    }
                }
            }
            if (!flag)
            {
                break;
            }
            else
            {
                flag = false;
            }
        }
    }

    if (index == start && !forward)
    {
        ++index;
    }
    return index;
}

float CLComString::SimilarString(const CLComString& str1, const CLComString& str2)
{
    if (str1 == "" || str2 == "")
    {
        return 0;
    }

    int countSameChar = 0;
    float percent = 0;
    string longStr = "";
    string shortStr = "";
    string tempSTR = "";
    int index = 0;
    int lastIndex = 0;

    if (str1.GetLength() > str2.GetLength())
    {
        longStr = str1.m_str;
        shortStr = str2.m_str;
    }
    else
    {
        longStr = str2.m_str;
        shortStr = str1.m_str;
    }

    for (unsigned int i = 0; i < shortStr.size(); ++i)
    {
        if (CLComFuncs::IsChinese(shortStr[i]))
        {
            tempSTR = shortStr.substr(i, 2);;

            if (str1.m_bhaveChinese)
            {
                index = CLComFuncs::FindMix(longStr, tempSTR, lastIndex, true);
            }
            else
            {
                index = longStr.find(tempSTR, lastIndex);
            }
            ++i;
            if (-1 == index)
            {
                continue;
            }
            else
            {
                lastIndex = (index + 2);
                countSameChar += 2;
            }
        }
        else
        {
            tempSTR = shortStr.substr(i, 1);;

            if (str1.m_bhaveChinese)
            {
                index = CLComFuncs::FindMix(longStr, tempSTR, lastIndex, true);
            }
            else
            {
                index = longStr.find(tempSTR, lastIndex);
            }
            if (-1 == index)
            {
                continue;
            }
            else
            {
                lastIndex = (index + 1);
                ++countSameChar;
            }

        }
    }
    percent = (float)countSameChar / longStr.size();

    return percent;
}
struct Spliters
{
    int position;
    int size;
    Spliters()
    {
        position = -1;
        size = 0;
    }
};
static bool compare_vpString(Spliters sa, Spliters sb)
{
    return sa.position < sb.position;
}
void CLComString::SplitString(vector<CLComString>& vecResult, CLComString spliter, const CLComString& source, bool fillNull)
{
    vector<CLComString> v_spliters;
    vector<CLComString>::iterator it;

    vector<Spliters> v_position;
    vector<Spliters>::iterator it_int;

    if (0 == spliter.GetLength() || 0 == source.GetLength())
    {
        return;
    }

    if (spliter != "," && string::npos != spliter.Find(","))
    {
        SplitString(v_spliters, ",", spliter, false);
    }
    else if (spliter.GetLength() > source.GetLength())
    {
        vecResult.push_back(source);
        return;
    }
    else
    {
        v_spliters.push_back(spliter);
    }

    int k = 0;

    for (it = v_spliters.begin(); it != v_spliters.end();)
    {
        //k = source.find_first_of(*it, k);

        k = source.Find(*it, k);

        //k = source.find_first_of(*it, k);
        if (-1 != k)
        {
            Spliters sp;
            sp.position = (int)k;
            sp.size = (int)(*it).GetLength();

            v_position.push_back(sp);
            k += (*it).GetLength();
        }
        else
        {
            ++it;
            k = 0;
        }
    }

    sort(v_position.begin(), v_position.end(), compare_vpString);


    k = 0;
    int start = 0;
    for (it_int = v_position.begin(); it_int != v_position.end(); ++it_int)
    {
        string temp = source.m_str.substr(start, size_t((*it_int).position) - start);

        if ("" != temp || fillNull)
        {
            vecResult.push_back(temp);
        }
        start = (*it_int).position + (*it_int).size;
    }


    if (start < (int)source.GetLength())
    {
        vecResult.push_back(source.m_str.substr(start, size_t(source.GetLength()) - start));
    }
}
